package com.ruoyi.common.utils.uuid;

import java.util.concurrent.atomic.AtomicInteger;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;

/**
 * 序列生成工具类
 * 提供基于时间戳、机器码和自增序号的唯一序列号生成功能。
 * 支持通用序列号与上传序列号两种类型。
 *
 * @author ruoyi
 */
public class Seq {
    // 通用序列类型标识
    public static final String commSeqType = "COMMON";

    // 上传序列类型标识
    public static final String uploadSeqType = "UPLOAD";

    // 通用接口序列计数器，初始值为1
    private static AtomicInteger commSeq = new AtomicInteger(1);

    // 上传接口序列计数器，初始值为1
    private static AtomicInteger uploadSeq = new AtomicInteger(1);

    // 机器标识码，用于区分不同节点或服务实例
    private static final String machineCode = "A";

    /**
     * 获取默认类型的序列号（通用类型）
     *
     * @return 返回格式为：yyMMddHHmmss + 机器标识 + 三位数字序号组成的字符串
     */
    public static String getId() {
        return getId(commSeqType);
    }

    /**
     * 根据指定类型获取序列号
     * 默认生成16位序列号，格式为：yyMMddHHmmss + 一位机器标识 + 3位长度循环递增字符串
     *
     * @param type 序列号类型，支持 COMMON 和 UPLOAD 类型
     * @return 返回对应类型的序列号字符串
     */
    public static String getId(String type) {
        AtomicInteger atomicInt = commSeq;
        if (uploadSeqType.equals(type)) {
            atomicInt = uploadSeq;
        }
        return getId(atomicInt, 3);
    }

    /**
     * 构造序列号核心方法
     * 拼接当前时间、机器码以及指定长度的递增序号
     *
     * @param atomicInt 自增原子整数对象，用于维护序号状态
     * @param length    序号部分的长度，决定最大可表示数值范围
     * @return 完整的序列号字符串
     */
    public static String getId(AtomicInteger atomicInt, int length) {
        String result = DateUtils.dateTimeNow();
        result += machineCode;
        result += getSeq(atomicInt, length);
        return result;
    }

    /**
     * 获取并更新递增序号字符串
     * 实现循环递增逻辑，并在达到上限时自动重置为1
     *
     * @param atomicInt 原子整数对象，保存当前序号状态
     * @param length    序号字符串的目标长度，不足则前补0
     * @return 左补零后的序号字符串
     */
    private synchronized static String getSeq(AtomicInteger atomicInt, int length) {
        // 先获取当前值再进行自增操作
        int value = atomicInt.getAndIncrement();

        // 计算该长度下允许的最大序号值（即10的length次方）
        int maxSeq = (int) Math.pow(10, length);
        if (atomicInt.get() >= maxSeq) {
            atomicInt.set(1); // 达到上限后重置为1
        }

        // 将数值转换为固定长度字符串，左侧填充0
        return StringUtils.padl(value, length);
    }
}
